﻿using System;
using System.Collections.Generic;
using System.Text;
using HBDotNet;
using System.Timers;
using System.Windows.Forms;
using System.Xml;
using System.Net;
using System.IO;

namespace Weather
{
    [HBDevice("World Weather Online")]
    public class Weather : HBDeviceBase
    {
        System.Timers.Timer timer = new System.Timers.Timer();
        int Interval = 0;
        double TimeZoneOffset = 100;

        public override bool OnInit(bool enabled)
        {
            if (enabled)
            {
                enabled = OnEnable();
            }
            base.OnInit(enabled);
            return true;
        }
        public override void OnShutdown()
        {
            // Stop the weather timer
            timer.Enabled = false;
            base.OnShutdown();
        }
        public override bool OnEnable()
        {            
            //Setup the timer
            timer.Interval = 3000;
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Enabled = true;
            return true;
        }
        public override bool OnDisable()
        {
            // Stop the weather timer
            timer.Enabled = false;
            return base.OnDisable();
        }
        public override void OnAboutBox()
        {
            MessageBox.Show("This plugin returns weather information from worldweatheronline.com website. You will require a free key to use this plugin. Go here http://www.worldweatheronline.com/register.aspx ");
        }
        protected override bool OnPropertyChangeRequest(HBDotNet.HBProperty hbProperty, string newValue)
        {
            if (hbProperty.Name == "Location Name" || hbProperty.Name == "Unit" || hbProperty.Name == "License Key")
            {
                // reset offset as location may have changed
                TimeZoneOffset = 100;
                // do a refresh in 1 sec
                timer.Interval = 1000;
            }

            return base.OnPropertyChangeRequest(hbProperty, newValue);
        }
        /// <summary>
        /// On install registers following properties
        /// </summary>
        /// <returns></returns>
        public override bool OnRegisterProperties()
        {
            // Weather.com account information
            Properties.Add(new HBProperty("License Key", "License Key", false, "", eIOType.ioInputAndOutput, true, true, true, false, ePropertyType.ptAlpha, "Enter the partner id.  This is available from http://www.worldweatheronline.com/register.aspx for free."));
            Properties.Add(new HBProperty("Location Name", "Location Name", false, "London, United Kingdom", eIOType.ioInputAndOutput, true, true, true, false, ePropertyType.ptAlpha, "Enter location (i.e. London, United Kingdom) Postcode/Zipcode or Latitude,Longitude or IP Address can also be used."));
            
            Properties.Add(new HBProperty("Image Location", "Image Location", false, "C:\\Program Files\\HouseBot\\Config\\Themes\\weather\\icons", eIOType.ioInputAndOutput, true, true, true, false, ePropertyType.ptAlpha, ""));
            Properties.Add(new HBProperty("Unit", "Unit", false, "Metric", eIOType.ioInputAndOutput, true, true, true, false, ePropertyType.ptAlpha, "Enter Metric or Standard."));
            HBModule.CreateDevicePropertyValue("Unit", "Metric");
            HBModule.CreateDevicePropertyValue("Unit", "Imperial");
            HBModule.CreateDevicePropertyValue("Unit", "Mixed");
            Properties.Add(new HBProperty("Interval", "Interval", false, "900", eIOType.ioInputAndOutput, true, true, true, false, ePropertyType.ptNumeric, ""));
            
            // Readonly  weather stats
            Properties.Add(new HBProperty("Current Time of Observation", "Current Time of Observation", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
            Properties.Add(new HBProperty("Current Temperature", "Current Temperature", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
            Properties.Add(new HBProperty("Current Weather Summary", "Current Weather Summary", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
            Properties.Add(new HBProperty("Current Weather Icon", "Current Weather Icon", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
            Properties.Add(new HBProperty("Current Wind Speed", "Current Wind Speed", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
            Properties.Add(new HBProperty("Current Wind Direction", "Current Wind Direction", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
            Properties.Add(new HBProperty("Current Wind Degree", "Current Wind Degree", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
            Properties.Add(new HBProperty("Current Rain", "Current Rain", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
            Properties.Add(new HBProperty("Current Humidity", "Current Humidity", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
            Properties.Add(new HBProperty("Current Visibility", "Current Visibility", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
            Properties.Add(new HBProperty("Current Pressure", "Current Pressure", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
            Properties.Add(new HBProperty("Current Cloud Cover", "Current Cloud Cover", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));

            // Next five days
            for (int d = 1; d < 6; d++)
            {
                Properties.Add(new HBProperty("Forecast " + d + " Day of Week", "Forecast " + d + " Day of Week", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
                Properties.Add(new HBProperty("Forecast " + d + " Date", "Forecast " + d + " Date", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
                Properties.Add(new HBProperty("Forecast " + d + " High Temperature", "Forecast " + d + " High Temperature", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
                Properties.Add(new HBProperty("Forecast " + d + " Low Temperature", "Forecast " + d + " Low Temperature", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
                Properties.Add(new HBProperty("Forecast " + d + " Wind Speed", "Forecast " + d + " Wind Speed", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
                Properties.Add(new HBProperty("Forecast " + d + " Wind Direction", "Forecast " + d + " Wind Direction", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
                Properties.Add(new HBProperty("Forecast " + d + " Wind Degree", "Forecast " + d + " Wind Degree", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
                Properties.Add(new HBProperty("Forecast " + d + " Icon", "Forecast " + d + " Icon", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
                Properties.Add(new HBProperty("Forecast " + d + " Summary", "Forecast " + d + " Summary", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
                Properties.Add(new HBProperty("Forecast " + d + " Rain", "Forecast " + d + " Rain", false, "", eIOType.ioInputOnly, true, true, true, false, ePropertyType.ptAlpha, ""));
            }
            return base.OnRegisterProperties();
        }
        public void SetProperty(string propertyName, string propertyValue)
        {
            Properties.GetPropertyByName(propertyName).CurrentValue = propertyValue;
        }
        public void SetProperty(string propertyName, double propertyValue)
        {
            Properties.GetPropertyByName(propertyName).CurrentValue = propertyValue.ToString();
        }
        public void SetProperty(string propertyName, double propertyValue, int decimalPrecision)
        {
            Properties.GetPropertyByName(propertyName).CurrentValue = propertyValue.ToString("F" + decimalPrecision.ToString());
        }
        public string GetProperty(string propertyName)
        {
            return Properties.GetPropertyByName(propertyName).CurrentValue;
        }
        /// <summary>
        /// Method is run on tick of timer
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            //Set interval
            if (!int.TryParse(GetProperty("Interval"), out Interval))
            {
                Interval = 0;
            }
            //If there was a problem then reset to 5 mins
            if (Interval < 1)
            {
                HBModule.TraceDeviceMessage(_deviceHandle, TRC_TYPE.ttError, "Interval setting is in wrong format.  Has been reset to 15 mins.");
                timer.Interval = 900000;
                SetProperty("Interval", 900);
            }
            else
            {
                timer.Interval = Interval * 1000;
            }

            UpdateWeather();
        }
        /// <summary>
        /// Method gets weather information from weather.com
        /// </summary>
        private void UpdateWeather()
        {
                        
            XmlDocument xDoc = new XmlDocument();
            var licenceKey = GetProperty("License Key");

            //get correct offset
            if (TimeZoneOffset == 100)
            {                
                if(licenceKey.Length != 29)
                {
                    xDoc.LoadXml(GetRssFeed("http://api.worldweatheronline.com/free/v1/tz.ashx?q=" + GetProperty("Location Name") + "&format=xml&key=" + licenceKey));
                }
                else
                {
                    xDoc.LoadXml(GetRssFeed("http://api.worldweatheronline.com/free/v2/tz.ashx?q=" + GetProperty("Location Name") + "&format=xml&key=" + licenceKey));
                }

                if (GetValue(xDoc, "/data/error/msg", "OK").Equals("OK"))
                {
                    double.TryParse(GetValue(xDoc,"/data/time_zone/utcOffset"),out TimeZoneOffset);
                }                
            }            
            
            //try
            //{
                //get xml
                 if(licenceKey.Length != 29)
                 {
                    xDoc.LoadXml(GetRssFeed("http://api.worldweatheronline.com/free/v1/weather.ashx?q=" + GetProperty("Location Name") + "&format=xml&num_of_days=5&key=" + licenceKey));
                 }
                 else
                 {
                     xDoc.LoadXml(GetRssFeed("http://api.worldweatheronline.com/free/v2/weather.ashx?q=" + GetProperty("Location Name") + "&format=xml&num_of_days=5&tp=24&key=" + licenceKey));
                 }
                     
                if (GetValue(xDoc, "/data/error/msg", "OK").Equals("OK"))
                {
                    if (licenceKey.Length != 29) { ParseXML(xDoc); }
                    else { ParseXMLv2(xDoc); }
                }
                // There was a problem so prompt it
                else
                {
                    HBModule.TraceDeviceMessage(_deviceHandle, TRC_TYPE.ttError, GetValue(xDoc, "/data/error/msg"));
                }
            //}
            //There was a error, could be internet down or weather.com
            //catch//(Exception ex)
            //{    
            //    // Internet down error, ignore
            //    // HBModule.TraceDeviceMessage(_deviceHandle, TRC_TYPE.ttError, ex.Message.ToString());                   
            //}
        }
        /// <summary>
        /// Parses weather.com XML
        /// </summary>
        /// <param name="xDoc"></param>
        private void ParseXML(XmlDocument xDoc)
        {
            try
            {
                //reformat icon location if required
                string sIconLocation = GetProperty("Image Location");
                if (!sIconLocation.EndsWith("\\"))
                    SetProperty("Image Location", sIconLocation + "\\");
   

                // Current Conditions                
                switch (GetProperty("Unit"))
                {
                    case "Metric":
                        UpdateProperty("Current Temperature", AddUnit(GetValue(xDoc, "/data/current_condition/temp_C"), "°C"));
                        UpdateProperty("Current Wind Speed", AddUnit(GetValue(xDoc, "/data/current_condition/windspeedKmph"), " kmph"));
                        break;
                    case "Imperial":
                        UpdateProperty("Current Temperature", AddUnit(GetValue(xDoc, "/data/current_condition/temp_F"), "°F"));
                        UpdateProperty("Current Wind Speed", AddUnit(GetValue(xDoc, "/data/current_condition/windspeedMiles"), " mph"));
                        break;
                    default:
                        UpdateProperty("Current Temperature", AddUnit(GetValue(xDoc, "/data/current_condition/temp_C"), "°C"));
                        UpdateProperty("Current Wind Speed", AddUnit(GetValue(xDoc, "/data/current_condition/windspeedMiles"), " mph"));
                        break;
                }
                UpdateProperty("Location Name", GetValue(xDoc, "/data/request/query"));
                UpdateProperty("Current Time of Observation", DateTime.Parse(GetValue(xDoc, "/data/current_condition/observation_time")).AddHours(TimeZoneOffset).ToString("hh:mm tt"));
                UpdateProperty("Current Weather Summary", GetValue(xDoc, "/data/current_condition/weatherDesc"));
                UpdateProperty("Current Weather Icon", sIconLocation + GetValue(xDoc, "/data/current_condition/weatherIconUrl").Remove(0, 1 + GetValue(xDoc, "/data/current_condition/weatherIconUrl").LastIndexOf("/")));
                UpdateProperty("Current Wind Direction", GetValue(xDoc, "/data/current_condition/winddir16Point"));
                UpdateProperty("Current Wind Degree", GetValue(xDoc, "/data/current_condition/winddirDegree"));
                UpdateProperty("Current Rain", AddUnit(GetValue(xDoc, "/data/current_condition/precipMM") , " mm"));
                UpdateProperty("Current Humidity", AddUnit(GetValue(xDoc, "/data/current_condition/humidity"),"%"));
                UpdateProperty("Current Visibility", GetValue(xDoc, "/data/current_condition/visibility"));
                UpdateProperty("Current Pressure", AddUnit(GetValue(xDoc, "/data/current_condition/pressure")," mb"));
                UpdateProperty("Current Cloud Cover",  AddUnit(GetValue(xDoc, "/data/current_condition/cloudcover"),"%"));
                
                // Next five days
                for (int d = 1; d < 6; d++)
                {
                    //Full day
                    UpdateProperty("Forecast " + d + " Day of Week", DateTime.Parse(GetValue(xDoc, "/data/weather[" + d + "]/date")).DayOfWeek.ToString());
                    UpdateProperty("Forecast " + d + " Date", DateTime.Parse(GetValue(xDoc, "/data/weather[" + d + "]/date")).ToLongDateString());

                    switch (GetProperty("Unit"))
                    {
                        case "Metric":
                            UpdateProperty("Forecast " + d + " High Temperature", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/tempMaxC"), "°C"));
                            UpdateProperty("Forecast " + d + " Low Temperature", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/tempMinC"), "°C"));
                            UpdateProperty("Forecast " + d + " Wind Speed", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/windspeedKmph"), " kmph"));
                            break;
                        case "Imperial":
                            UpdateProperty("Forecast " + d + " High Temperature", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/tempMaxF"), "°F"));
                            UpdateProperty("Forecast " + d + " Low Temperature", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/tempMinF"), "°F"));
                            UpdateProperty("Forecast " + d + " Wind Speed", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/windspeedMiles"), " mph"));
                            break;
                        default:
                            UpdateProperty("Forecast " + d + " High Temperature", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/tempMaxC"), "°C"));
                            UpdateProperty("Forecast " + d + " Low Temperature", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/tempMinC"), "°C"));
                            UpdateProperty("Forecast " + d + " Wind Speed", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/windspeedMiles"), " mph"));
                            break;
                    }

                    UpdateProperty("Forecast " + d + " Wind Direction", GetValue(xDoc, "/data/weather[" + d + "]/winddirection"));
                    UpdateProperty("Forecast " + d + " Wind Degree", GetValue(xDoc, "/data/weather[" + d + "]/winddirDegree"));
                    UpdateProperty("Forecast " + d + " Icon", sIconLocation + GetValue(xDoc, "/data/weather[" + d + "]/weatherIconUrl").Remove(0, 1 + GetValue(xDoc, "/data/weather[" + d + "]/weatherIconUrl").LastIndexOf("/")));
                    UpdateProperty("Forecast " + d + " Summary", GetValue(xDoc, "/data/weather[" + d + "]/weatherDesc"));
                    UpdateProperty("Forecast " + d + " Rain", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/precipMM"), " mm"));
                }
            }
            catch (Exception e)
            {
                HBModule.TraceDeviceMessage(_deviceHandle, TRC_TYPE.ttError, "Error parsing XML: " + e.Message);
            }
        }

        /// <summary>
        /// Parses weather.com XML for api v2
        /// </summary>
        /// <param name="xDoc"></param>
        private void ParseXMLv2(XmlDocument xDoc)
        {
            try
            {
                //reformat icon location if required
                string sIconLocation = GetProperty("Image Location");
                if (!sIconLocation.EndsWith("\\"))
                    SetProperty("Image Location", sIconLocation + "\\");


                // Current Conditions                
                switch (GetProperty("Unit"))
                {
                    case "Metric":
                        UpdateProperty("Current Temperature", AddUnit(GetValue(xDoc, "/data/current_condition/temp_C"), "°C"));
                        UpdateProperty("Current Wind Speed", AddUnit(GetValue(xDoc, "/data/current_condition/windspeedKmph"), " kmph"));
                        break;
                    case "Imperial":
                        UpdateProperty("Current Temperature", AddUnit(GetValue(xDoc, "/data/current_condition/temp_F"), "°F"));
                        UpdateProperty("Current Wind Speed", AddUnit(GetValue(xDoc, "/data/current_condition/windspeedMiles"), " mph"));
                        break;
                    default:
                        UpdateProperty("Current Temperature", AddUnit(GetValue(xDoc, "/data/current_condition/temp_C"), "°C"));
                        UpdateProperty("Current Wind Speed", AddUnit(GetValue(xDoc, "/data/current_condition/windspeedMiles"), " mph"));
                        break;
                }
                UpdateProperty("Location Name", GetValue(xDoc, "/data/request/query"));
                UpdateProperty("Current Time of Observation", DateTime.Parse(GetValue(xDoc, "/data/current_condition/observation_time")).AddHours(TimeZoneOffset).ToString("hh:mm tt"));
                UpdateProperty("Current Weather Summary", GetValue(xDoc, "/data/current_condition/weatherDesc"));
                UpdateProperty("Current Weather Icon", sIconLocation + GetValue(xDoc, "/data/current_condition/weatherIconUrl").Remove(0, 1 + GetValue(xDoc, "/data/current_condition/weatherIconUrl").LastIndexOf("/")));
                UpdateProperty("Current Wind Direction", GetValue(xDoc, "/data/current_condition/winddir16Point"));
                UpdateProperty("Current Wind Degree", GetValue(xDoc, "/data/current_condition/winddirDegree"));
                UpdateProperty("Current Rain", AddUnit(GetValue(xDoc, "/data/current_condition/precipMM"), " mm"));
                UpdateProperty("Current Humidity", AddUnit(GetValue(xDoc, "/data/current_condition/humidity"), "%"));
                UpdateProperty("Current Visibility", GetValue(xDoc, "/data/current_condition/visibility"));
                UpdateProperty("Current Pressure", AddUnit(GetValue(xDoc, "/data/current_condition/pressure"), " mb"));
                UpdateProperty("Current Cloud Cover", AddUnit(GetValue(xDoc, "/data/current_condition/cloudcover"), "%"));

                // Next five days
                for (int d = 1; d < 6; d++)
                {
                    //Full day
                    UpdateProperty("Forecast " + d + " Day of Week", DateTime.Parse(GetValue(xDoc, "/data/weather[" + d + "]/date")).DayOfWeek.ToString());
                    UpdateProperty("Forecast " + d + " Date", DateTime.Parse(GetValue(xDoc, "/data/weather[" + d + "]/date")).ToLongDateString());

                    switch (GetProperty("Unit"))
                    {
                        case "Metric":
                            UpdateProperty("Forecast " + d + " High Temperature", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/maxtempC"), "°C"));
                            UpdateProperty("Forecast " + d + " Low Temperature", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/mintempC"), "°C"));
                            UpdateProperty("Forecast " + d + " Wind Speed", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/hourly/windspeedKmph"), " kmph"));
                            break;
                        case "Imperial":
                            UpdateProperty("Forecast " + d + " High Temperature", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/maxtempF"), "°F"));
                            UpdateProperty("Forecast " + d + " Low Temperature", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/mintempF"), "°F"));
                            UpdateProperty("Forecast " + d + " Wind Speed", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/hourly/windspeedMiles"), " mph"));
                            break;
                        default:
                            UpdateProperty("Forecast " + d + " High Temperature", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/maxtempC"), "°C"));
                            UpdateProperty("Forecast " + d + " Low Temperature", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/mintempC"), "°C"));
                            UpdateProperty("Forecast " + d + " Wind Speed", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/hourly/windspeedMiles"), " mph"));
                            break;
                    }

                    UpdateProperty("Forecast " + d + " Wind Direction", GetValue(xDoc, "/data/weather[" + d + "]/hourly/winddir16Point"));
                    UpdateProperty("Forecast " + d + " Wind Degree", GetValue(xDoc, "/data/weather[" + d + "]/hourly/winddirDegree"));
                    UpdateProperty("Forecast " + d + " Icon", sIconLocation + GetValue(xDoc, "/data/weather[" + d + "]/hourly/weatherIconUrl").Remove(0, 1 + GetValue(xDoc, "/data/weather[" + d + "]/hourly/weatherIconUrl").LastIndexOf("/")));
                    UpdateProperty("Forecast " + d + " Summary", GetValue(xDoc, "/data/weather[" + d + "]/hourly/weatherDesc"));
                    UpdateProperty("Forecast " + d + " Rain", AddUnit(GetValue(xDoc, "/data/weather[" + d + "]/hourly/precipMM"), " mm"));
                }
            }
            catch (Exception e)
            {
                HBModule.TraceDeviceMessage(_deviceHandle, TRC_TYPE.ttError, "Error parsing XML: " + e.Message);
            }
        }

        /// <summary>
        /// Adds unit to the strings
        /// </summary>
        /// <param name="value"></param>
        /// <param name="unit"></param>Allan    
        /// <returns></returns>
        private string AddUnit(string value, string unit)
        {
            if (value.Trim().Equals(string.Empty) ||
                value.ToLower().Trim().Equals("n/a"))
            {
                return value;
            }
            else
            {
                return value + unit;
            }
        }
        /// <summary>
        /// Format for weather.com icon image
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        //private string FormatImage(string value)
        //{
        //    //if (value.Length.Equals(1))
        //    //{
        //    //    return "0"+value+".png";
        //    //}
        //    //else
        //    //{

        //    if (File.Exists(value + ".png"))
        //        return value + ".png";
        //    else if (File.Exists(value + ".gif"))
        //        return value + ".gif";
        //    else if (File.Exists(value + ".jpg"))
        //        return value + ".jpg";
        //    else if (File.Exists(value + ".jpeg"))
        //        return value + ".jpeg";
        //    else
        //    {
        //        HBModule.TraceDeviceMessage(_deviceHandle, TRC_TYPE.ttError, "Unable to find image "+value+".png|gif|jpg|jpeg");
        //        return "";
        //    }
        //}
        /// <summary>
        /// Returns rss feed as a string
        /// </summary>
        /// <param name="url">http url of rss feed</param>
        /// <returns>xml as string</returns>
        private string GetRssFeed(string url)
        {
            try
            {

                WebRequest request = WebRequest.Create(url);

                //Uncomment code if proxy is required
                //WebProxy proxy = new WebProxy("http://ip:port/", true);
                //proxy.Credentials = 
                //    new NetworkCredential( 
                //        "username", 
                //        "password", 
                //        "domain");
                //request.Proxy = proxy;

                // Send the 'HttpWebRequest' and wait for response. 
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    using (Stream stream = response.GetResponseStream())
                    {
                        Encoding ec = Encoding.GetEncoding("utf-8");

                        using (StreamReader reader = new StreamReader(stream, ec))
                        {
                            return reader.ReadToEnd();
                        }
                    }
                }
            }
            catch (Exception e)
            {
                return  @"<data>
                            <error>
                            <msg>
                            "+e.Message.ToString()+@"
                            </msg>
                            </error>
                          </data>";
            }
        }
        /// <summary>
        /// Parses Xml using xpath and returns inner xml
        /// </summary>
        /// <param name="xDoc">XmlDocument to parse</param>
        /// <param name="xpath">XPath statement to use</param>
        /// <returns>InnerXml string</returns>
        private string GetValue(XmlDocument xDoc, string xpath)
        {
            return GetValue(xDoc, xpath, string.Empty);
        }
        /// <summary>
        /// Parses Xml using xpath and returns inner xml
        /// </summary>
        /// <param name="xDoc">XmlDocument to parse</param>
        /// <param name="xpath">XPath statement to use</param>
        /// <param name="returnValue">String that will be returned if null or error or blank</param>
        /// <returns>InnerXml string</returns>
        private string GetValue(XmlDocument xDoc, string xpath, string returnValue)
        {
            try
            {
                string _returnValue;
                
                _returnValue = xDoc.SelectSingleNode(xpath).InnerXml;

                if(_returnValue.StartsWith("<![CDATA["))
                    _returnValue = ((XmlCDataSection)(xDoc.SelectSingleNode(xpath).ChildNodes[0])).Data;

                if (_returnValue.Equals(string.Empty))
                    _returnValue = returnValue;

                return _returnValue;
            }
            catch
            {
                return returnValue;
            }
        }
        /// <summary>
        /// Sends message to UI, update only if changed
        /// </summary>
        /// <param name="deviceName"></param>
        /// <param name="value"></param>
        private void UpdateProperty(string deviceName, string value)
        {
            if(!GetProperty(deviceName).Equals(value))
                SetProperty(deviceName, value);
        }
        
    }
}